#!/usr/bin/env python3
"""
统一配置验证器
提供配置文件验证、自动修复和安全检查功能
"""

import os
import json
import yaml
import logging
from typing import Dict, Any, List, Optional, Union, Tuple
from pathlib import Path
from dataclasses import dataclass
from enum import Enum
import re
import ipaddress
from urllib.parse import urlparse

from .error_handler import (
    EnhancedErrorHandler, ErrorSeverity, ErrorCategory, 
    error_handler, handle_critical_error
)

class ConfigType(Enum):
    """配置文件类型"""
    JSON = "json"
    YAML = "yaml"
    INI = "ini"
    ENV = "env"

class ValidationLevel(Enum):
    """验证级别"""
    BASIC = "basic"      # 基本语法检查
    STANDARD = "standard"  # 标准验证
    STRICT = "strict"    # 严格验证
    SECURITY = "security"  # 安全验证

@dataclass
class ValidationResult:
    """验证结果"""
    is_valid: bool
    errors: List[str]
    warnings: List[str]
    suggestions: List[str]
    auto_fixes: List[str]
    security_issues: List[str]

@dataclass
class ConfigSchema:
    """配置模式定义"""
    required_fields: List[str]
    optional_fields: List[str]
    field_types: Dict[str, type]
    field_validators: Dict[str, callable]
    default_values: Dict[str, Any]
    security_rules: Dict[str, Any]

class EnhancedConfigValidator:
    """增强的配置验证器"""
    
    def __init__(self, log_dir: str = "logs"):
        """初始化配置验证器"""
        self.error_handler = EnhancedErrorHandler(
            log_dir=log_dir,
            enable_recovery=True
        )
        self.logger = logging.getLogger(__name__)
        
        # 预定义的配置模式
        self.schemas = {
            "test_config": self._create_test_config_schema(),
            "network_config": self._create_network_config_schema(),
            "security_config": self._create_security_config_schema(),
            "persistence_config": self._create_persistence_config_schema()
        }
        
        # 安全规则
        self.security_patterns = {
            "password": re.compile(r'password|passwd|pwd', re.IGNORECASE),
            "api_key": re.compile(r'api[_-]?key|apikey|token', re.IGNORECASE),
            "secret": re.compile(r'secret|private[_-]?key', re.IGNORECASE),
            "sensitive": re.compile(r'sensitive|confidential|private', re.IGNORECASE)
        }
    
    def _create_test_config_schema(self) -> ConfigSchema:
        """创建测试配置模式"""
        return ConfigSchema(
            required_fields=["target_host", "test_types", "output_dir"],
            optional_fields=["timeout", "retry_count", "log_level"],
            field_types={
                "target_host": str,
                "test_types": list,
                "output_dir": str,
                "timeout": int,
                "retry_count": int,
                "log_level": str
            },
            field_validators={
                "target_host": self._validate_host,
                "test_types": self._validate_test_types,
                "output_dir": self._validate_directory,
                "timeout": lambda x: x > 0,
                "retry_count": lambda x: 0 <= x <= 10,
                "log_level": lambda x: x.upper() in ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
            },
            default_values={
                "timeout": 300,
                "retry_count": 3,
                "log_level": "INFO"
            },
            security_rules={
                "no_plaintext_passwords": True,
                "validate_paths": True,
                "check_permissions": True
            }
        )
    
    def _create_network_config_schema(self) -> ConfigSchema:
        """创建网络配置模式"""
        return ConfigSchema(
            required_fields=["host", "port"],
            optional_fields=["protocol", "ssl_verify", "proxy"],
            field_types={
                "host": str,
                "port": int,
                "protocol": str,
                "ssl_verify": bool,
                "proxy": str
            },
            field_validators={
                "host": self._validate_host,
                "port": lambda x: 1 <= x <= 65535,
                "protocol": lambda x: x.lower() in ["http", "https", "tcp", "udp"],
                "proxy": self._validate_url
            },
            default_values={
                "protocol": "https",
                "ssl_verify": True
            },
            security_rules={
                "require_ssl": True,
                "validate_certificates": True
            }
        )
    
    def _create_security_config_schema(self) -> ConfigSchema:
        """创建安全配置模式"""
        return ConfigSchema(
            required_fields=["auth_method", "permissions"],
            optional_fields=["encryption", "audit_log", "session_timeout"],
            field_types={
                "auth_method": str,
                "permissions": list,
                "encryption": bool,
                "audit_log": bool,
                "session_timeout": int
            },
            field_validators={
                "auth_method": lambda x: x in ["key", "password", "certificate", "token"],
                "permissions": self._validate_permissions,
                "session_timeout": lambda x: x > 0
            },
            default_values={
                "encryption": True,
                "audit_log": True,
                "session_timeout": 3600
            },
            security_rules={
                "require_encryption": True,
                "audit_required": True,
                "strong_auth": True
            }
        )
    
    def _create_persistence_config_schema(self) -> ConfigSchema:
        """创建持久化配置模式"""
        return ConfigSchema(
            required_fields=["methods", "targets"],
            optional_fields=["cleanup", "stealth_level", "backup"],
            field_types={
                "methods": list,
                "targets": list,
                "cleanup": bool,
                "stealth_level": int,
                "backup": bool
            },
            field_validators={
                "methods": self._validate_persistence_methods,
                "targets": self._validate_targets,
                "stealth_level": lambda x: 1 <= x <= 5
            },
            default_values={
                "cleanup": True,
                "stealth_level": 3,
                "backup": True
            },
            security_rules={
                "validate_methods": True,
                "check_targets": True
            }
        )
    
    @error_handler(severity=ErrorSeverity.HIGH, category=ErrorCategory.VALIDATION)
    def validate_config_file(self, 
                           file_path: str, 
                           schema_name: Optional[str] = None,
                           validation_level: ValidationLevel = ValidationLevel.STANDARD) -> ValidationResult:
        """验证配置文件"""
        if not os.path.exists(file_path):
            return ValidationResult(
                is_valid=False,
                errors=[f"配置文件不存在: {file_path}"],
                warnings=[],
                suggestions=[f"请创建配置文件: {file_path}"],
                auto_fixes=[],
                security_issues=[]
            )
        
        # 检测配置文件类型
        config_type = self._detect_config_type(file_path)
        
        # 加载配置
        try:
            config_data = self._load_config(file_path, config_type)
        except Exception as e:
            return ValidationResult(
                is_valid=False,
                errors=[f"配置文件格式错误: {str(e)}"],
                warnings=[],
                suggestions=["检查配置文件语法"],
                auto_fixes=[],
                security_issues=[]
            )
        
        # 执行验证
        return self._validate_config_data(config_data, schema_name, validation_level)
    
    @error_handler(severity=ErrorSeverity.MEDIUM, category=ErrorCategory.VALIDATION)
    def validate_config_data(self, 
                           config_data: Dict[str, Any],
                           schema_name: Optional[str] = None,
                           validation_level: ValidationLevel = ValidationLevel.STANDARD) -> ValidationResult:
        """验证配置数据"""
        return self._validate_config_data(config_data, schema_name, validation_level)
    
    def _validate_config_data(self, 
                            config_data: Dict[str, Any],
                            schema_name: Optional[str] = None,
                            validation_level: ValidationLevel = ValidationLevel.STANDARD) -> ValidationResult:
        """内部配置数据验证"""
        errors = []
        warnings = []
        suggestions = []
        auto_fixes = []
        security_issues = []
        
        # 基本验证
        if validation_level in [ValidationLevel.BASIC, ValidationLevel.STANDARD, ValidationLevel.STRICT, ValidationLevel.SECURITY]:
            if not isinstance(config_data, dict):
                errors.append("配置数据必须是字典格式")
                return ValidationResult(False, errors, warnings, suggestions, auto_fixes, security_issues)
        
        # 模式验证
        if schema_name and schema_name in self.schemas:
            schema = self.schemas[schema_name]
            schema_result = self._validate_against_schema(config_data, schema, validation_level)
            errors.extend(schema_result.errors)
            warnings.extend(schema_result.warnings)
            suggestions.extend(schema_result.suggestions)
            auto_fixes.extend(schema_result.auto_fixes)
            security_issues.extend(schema_result.security_issues)
        
        # 安全验证
        if validation_level in [ValidationLevel.STRICT, ValidationLevel.SECURITY]:
            security_result = self._validate_security(config_data)
            security_issues.extend(security_result)
        
        # 通用验证
        general_result = self._validate_general_rules(config_data, validation_level)
        warnings.extend(general_result.get("warnings", []))
        suggestions.extend(general_result.get("suggestions", []))
        
        is_valid = len(errors) == 0
        return ValidationResult(is_valid, errors, warnings, suggestions, auto_fixes, security_issues)
    
    def _validate_against_schema(self, 
                               config_data: Dict[str, Any], 
                               schema: ConfigSchema,
                               validation_level: ValidationLevel) -> ValidationResult:
        """根据模式验证配置"""
        errors = []
        warnings = []
        suggestions = []
        auto_fixes = []
        security_issues = []
        
        # 检查必需字段
        for field in schema.required_fields:
            if field not in config_data:
                errors.append(f"缺少必需字段: {field}")
                if field in schema.default_values:
                    auto_fixes.append(f"添加默认值 {field}: {schema.default_values[field]}")
        
        # 检查字段类型
        for field, expected_type in schema.field_types.items():
            if field in config_data:
                if not isinstance(config_data[field], expected_type):
                    errors.append(f"字段 {field} 类型错误，期望 {expected_type.__name__}，实际 {type(config_data[field]).__name__}")
        
        # 执行字段验证器
        for field, validator in schema.field_validators.items():
            if field in config_data:
                try:
                    if not validator(config_data[field]):
                        errors.append(f"字段 {field} 验证失败")
                except Exception as e:
                    errors.append(f"字段 {field} 验证器错误: {str(e)}")
        
        # 检查未知字段
        if validation_level in [ValidationLevel.STRICT, ValidationLevel.SECURITY]:
            known_fields = set(schema.required_fields + schema.optional_fields)
            unknown_fields = set(config_data.keys()) - known_fields
            if unknown_fields:
                warnings.extend([f"未知字段: {field}" for field in unknown_fields])
        
        return ValidationResult(True, errors, warnings, suggestions, auto_fixes, security_issues)
    
    def _validate_security(self, config_data: Dict[str, Any]) -> List[str]:
        """安全验证"""
        security_issues = []
        
        # 检查敏感信息
        for key, value in config_data.items():
            if isinstance(value, str):
                for pattern_name, pattern in self.security_patterns.items():
                    if pattern.search(key):
                        if len(value) < 8:
                            security_issues.append(f"字段 {key} 可能包含弱{pattern_name}")
                        if value.lower() in ["password", "123456", "admin", "root"]:
                            security_issues.append(f"字段 {key} 包含常见弱密码")
        
        # 检查路径安全
        for key, value in config_data.items():
            if isinstance(value, str) and ("path" in key.lower() or "dir" in key.lower()):
                if "../" in value or "..\\" in value:
                    security_issues.append(f"路径 {key} 包含危险的相对路径")
                if value.startswith("/tmp") or value.startswith("C:\\Temp"):
                    security_issues.append(f"路径 {key} 指向临时目录，可能不安全")
        
        return security_issues
    
    def _validate_general_rules(self, config_data: Dict[str, Any], validation_level: ValidationLevel) -> Dict[str, List[str]]:
        """通用规则验证"""
        warnings = []
        suggestions = []
        
        # 检查空值
        for key, value in config_data.items():
            if value is None or value == "":
                warnings.append(f"字段 {key} 为空")
        
        # 检查配置完整性
        if validation_level in [ValidationLevel.STRICT, ValidationLevel.SECURITY]:
            if len(config_data) < 3:
                suggestions.append("配置项较少，建议添加更多配置以提高功能性")
        
        return {"warnings": warnings, "suggestions": suggestions}
    
    @error_handler(severity=ErrorSeverity.MEDIUM, category=ErrorCategory.IO)
    def auto_fix_config(self, 
                       file_path: str, 
                       validation_result: ValidationResult,
                       backup: bool = True) -> bool:
        """自动修复配置文件"""
        if not validation_result.auto_fixes:
            return True
        
        # 备份原文件
        if backup:
            backup_path = f"{file_path}.backup"
            try:
                import shutil
                shutil.copy2(file_path, backup_path)
                self.logger.info(f"已备份配置文件到: {backup_path}")
            except Exception as e:
                self.logger.error(f"备份失败: {str(e)}")
                return False
        
        # 应用修复
        try:
            config_type = self._detect_config_type(file_path)
            config_data = self._load_config(file_path, config_type)
            
            # 应用自动修复
            for fix in validation_result.auto_fixes:
                self._apply_fix(config_data, fix)
            
            # 保存修复后的配置
            self._save_config(file_path, config_data, config_type)
            self.logger.info(f"已自动修复配置文件: {file_path}")
            return True
            
        except Exception as e:
            self.logger.error(f"自动修复失败: {str(e)}")
            return False
    
    def _detect_config_type(self, file_path: str) -> ConfigType:
        """检测配置文件类型"""
        ext = Path(file_path).suffix.lower()
        if ext in [".json"]:
            return ConfigType.JSON
        elif ext in [".yaml", ".yml"]:
            return ConfigType.YAML
        elif ext in [".ini", ".cfg"]:
            return ConfigType.INI
        elif ext in [".env"]:
            return ConfigType.ENV
        else:
            # 尝试根据内容检测
            try:
                with open(file_path, 'r', encoding='utf-8') as f:
                    content = f.read().strip()
                    if content.startswith('{') and content.endswith('}'):
                        return ConfigType.JSON
                    elif '=' in content and not content.startswith('['):
                        return ConfigType.ENV
                    else:
                        return ConfigType.YAML
            except:
                return ConfigType.JSON
    
    def _load_config(self, file_path: str, config_type: ConfigType) -> Dict[str, Any]:
        """加载配置文件"""
        with open(file_path, 'r', encoding='utf-8') as f:
            if config_type == ConfigType.JSON:
                return json.load(f)
            elif config_type == ConfigType.YAML:
                return yaml.safe_load(f) or {}
            elif config_type == ConfigType.INI:
                import configparser
                parser = configparser.ConfigParser()
                parser.read(file_path)
                return {section: dict(parser[section]) for section in parser.sections()}
            elif config_type == ConfigType.ENV:
                config = {}
                for line in f:
                    line = line.strip()
                    if line and not line.startswith('#') and '=' in line:
                        key, value = line.split('=', 1)
                        config[key.strip()] = value.strip()
                return config
            else:
                raise ValueError(f"不支持的配置类型: {config_type}")
    
    def _save_config(self, file_path: str, config_data: Dict[str, Any], config_type: ConfigType):
        """保存配置文件"""
        with open(file_path, 'w', encoding='utf-8') as f:
            if config_type == ConfigType.JSON:
                json.dump(config_data, f, indent=2, ensure_ascii=False)
            elif config_type == ConfigType.YAML:
                yaml.dump(config_data, f, default_flow_style=False, allow_unicode=True)
            elif config_type == ConfigType.INI:
                import configparser
                parser = configparser.ConfigParser()
                for section, values in config_data.items():
                    parser[section] = values
                parser.write(f)
            elif config_type == ConfigType.ENV:
                for key, value in config_data.items():
                    f.write(f"{key}={value}\n")
    
    def _apply_fix(self, config_data: Dict[str, Any], fix: str):
        """应用修复"""
        # 简单的修复解析（实际实现可能更复杂）
        if "添加默认值" in fix:
            # 解析 "添加默认值 field: value" 格式
            parts = fix.split("添加默认值")[1].strip().split(":", 1)
            if len(parts) == 2:
                field = parts[0].strip()
                value = parts[1].strip()
                try:
                    # 尝试解析值类型
                    if value.lower() in ["true", "false"]:
                        config_data[field] = value.lower() == "true"
                    elif value.isdigit():
                        config_data[field] = int(value)
                    else:
                        config_data[field] = value
                except:
                    config_data[field] = value
    
    # 验证器方法
    def _validate_host(self, host: str) -> bool:
        """验证主机地址"""
        try:
            # 检查IP地址
            ipaddress.ip_address(host)
            return True
        except:
            # 检查域名格式
            if re.match(r'^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*$', host):
                return True
            return False
    
    def _validate_url(self, url: str) -> bool:
        """验证URL格式"""
        try:
            result = urlparse(url)
            return all([result.scheme, result.netloc])
        except:
            return False
    
    def _validate_directory(self, path: str) -> bool:
        """验证目录路径"""
        try:
            # 检查路径格式
            Path(path)
            return True
        except:
            return False
    
    def _validate_test_types(self, test_types: List[str]) -> bool:
        """验证测试类型"""
        valid_types = [
            "privilege_escalation", "persistence", "edr_evasion", 
            "log_cleanup", "network_penetration", "lateral_movement"
        ]
        return all(t in valid_types for t in test_types)
    
    def _validate_permissions(self, permissions: List[str]) -> bool:
        """验证权限列表"""
        valid_permissions = ["read", "write", "execute", "admin", "root"]
        return all(p in valid_permissions for p in permissions)
    
    def _validate_persistence_methods(self, methods: List[str]) -> bool:
        """验证持久化方法"""
        valid_methods = [
            "systemd", "cron", "ssh_key", "user_account", 
            "startup_script", "kernel_module"
        ]
        return all(m in valid_methods for m in methods)
    
    def _validate_targets(self, targets: List[str]) -> bool:
        """验证目标列表"""
        return all(self._validate_host(target) for target in targets)

# 全局配置验证器实例
config_validator = EnhancedConfigValidator()

def validate_config(file_path: str, 
                   schema_name: Optional[str] = None,
                   validation_level: ValidationLevel = ValidationLevel.STANDARD) -> ValidationResult:
    """便捷的配置验证函数"""
    return config_validator.validate_config_file(file_path, schema_name, validation_level)

def auto_fix_config(file_path: str, backup: bool = True) -> bool:
    """便捷的配置自动修复函数"""
    result = validate_config(file_path)
    if result.auto_fixes:
        return config_validator.auto_fix_config(file_path, result, backup)
    return True